/******************************************************************* DOExchange.c It's a try to do the Exchange work within a dopus popup menu. Since nothing of the commodities.library is really documented, this source may be wrong. If you know more, you may change/add what is to do... SO BE WARNED... - THIS IS A HACK !! (even if it seems to be OK) Initial idea by Jens Weyer. *********************************************************************/ #include "includes/DOExchange.h" /********************************************************************/ // some prototypes ULONG __asm __saveds New_Proc_Startup( register __a0 IPCData *ipc, register __a1 DOE_Data *dd ); void __saveds New_Proc( void ); void CleanUp( DOE_Data *dd, IPCData *ipc ); BOOL OpenWin( DOE_Data *dd ); void BorderDraw( DOE_Data *dd, BOOL invers ); BOOL InitPopupMenu( DOE_Data *dd ); APTR CreateSubMenu( DOE_Data *dd, ULONG from, ULONG to ); void ClearPopupMenu( DOE_Data *dd ); BOOL DoMenu( DOE_Data *dd ); BOOL HandleWin( DOE_Data *dd ); BOOL HandleCX( DOE_Data *dd ); BOOL HandleNotify( DOE_Data *dd ); BOOL HandleIPC( DOE_Data *dd ); BOOL SendCxMsg( CX_OBJ *cxobj, ULONG type, struct MsgPort *reply_to ); BOOL WriteConfig( DOE_Data *dd ); BOOL ReadConfig( DOE_Data *dd ); /********************************************************************/ // it is surely useful to detach here void DOExchange( STRPTR args, struct Screen *screen, IPCData *ipc ) { DOE_Data *dd; FuncArgs *fargs; if( !exchange ) { if( (dd = AllocMemH(mempool, sizeof(DOE_Data))) ) { dd->screen = screen; dd->a4 = getreg( REG_A4 ); dd->module = (struct Library *) getreg( REG_A6 ); dd->library = DOpusBase; IPC_Launch( 0, &exchange, // pointer to pointer to the IPC of the new process, for storing... "DOpus Exchange", // name of the new process (ULONG) New_Proc, // entrypoint of the new process 4096, // stack to use (ULONG) dd, // data to pass to the new process DOSBase ); // pointer to dos.library if( !exchange ) // if detaching failed... { FreeMemH( dd ); return; } } } if( args ) { if( (fargs = ParseArgs(FUNC0_TEMPLATE, args)) ) { ULONG cmd = 0, counter; PassData *pd; for( counter = 0; counter < TEMPLATE_COUNT; counter++ ) if( fargs->FA_Arguments[counter] ) cmd |= 1 << counter; if( (pd = AllocVec(sizeof(PassData), MEMF_CLEAR)) ) { pd->FrontPen = ARG_TC ? *(ULONG *) ARG_TC : NULL; pd->BackPen = ARG_BGC ? *(ULONG *) ARG_BGC : NULL; pd->name = ARG_NAME ? (STRPTR) ARG_NAME : NULL; IPC_Command( exchange, cmd, NULL, NULL, pd, // FreeVec the data automatically REPLY_NO_PORT ); } DisposeArgs( fargs ); } } } /********************************************************************/ ULONG __asm __saveds New_Proc_Startup( register __a0 IPCData *ipc, register __a1 DOE_Data *dd ) { struct Library *DOpusBase; putreg( REG_A4, dd->a4 ); dd->ipc = ipc; DOpusBase = dd->library; // now follows our initialization dd->module->lib_OpenCnt++; // the default button text dd->itext.IText = DOpusGetString( locale, MSG_TEXT ); dd->itext.FrontPen = 1; ReadConfig( dd ); if( strlen(dd->name) ) dd->itext.IText = dd->name; // install our notify if( !(dd->notify_port = CreateMsgPort()) || !(dd->notify_handle = AddNotifyRequest(DN_OPUS_HIDE | DN_OPUS_SHOW | DN_OPUS_QUIT | DN_CLOSE_WORKBENCH | DN_OPEN_WORKBENCH | DN_RESET_WORKBENCH, NULL, dd->notify_port)) ) return FALSE; // fill our newbroker structure dd->nb.nb_Version = NB_VERSION; dd->nb.nb_Name = DOpusGetString( locale, FUNC0_DESCRIPTION ); dd->nb.nb_Title = dd->nb.nb_Name; dd->nb.nb_Descr = DOpusGetString( locale, MSG_CX_DESCR ); dd->nb.nb_Unique = NBU_UNIQUE|NBU_NOTIFY; dd->nb.nb_Flags = COF_SHOW_HIDE; // create the broker if( !(dd->nb.nb_Port = CreateMsgPort()) || !(dd->our_cxobj = CxBroker(&dd->nb, (LONG *) &dd->signals)) || dd->signals || !(dd->sender = CreateMsgPort()) ) return FALSE; return TRUE; // all was successfully } void __saveds New_Proc( void ) { DOE_Data *dd; IPCData *ipc; struct Library *DOpusBase; if( !(DOpusBase = (struct Library *) FindName(&((struct ExecBase *)*((ULONG *)4))->LibList, "dopus5.library")) ) return; ipc = IPC_ProcStartup( (ULONG *) &dd, New_Proc_Startup ); putreg( REG_A4, dd->a4 ); if( !ipc ) { if( dd ) CleanUp( dd, dd->ipc ); return; } // make our broker aktive ActivateCxObj( dd->our_cxobj, TRUE ); // open the window (looks like a dopus button) if( OpenWin(dd) ) { while( TRUE ) { dd->signals = Wait( 1 << dd->sender->mp_SigBit | // reply port of our sended messages 1 << dd->nb.nb_Port->mp_SigBit | 1 << dd->notify_port->mp_SigBit | 1 << dd->ipc->command_port->mp_SigBit | // ipc messages (dd->win ? 1 << dd->win->UserPort->mp_SigBit : NULL) ); // IDCMP messages if( dd->signals & 1 << dd->sender->mp_SigBit ) // our message does return { while( (dd->fmsg = (FakeMsg *) GetMsg(dd->sender)) ) FreeMemH( dd->fmsg ); // we have only to free the memory } dd->stop = FALSE; if( dd->signals & 1 << dd->nb.nb_Port->mp_SigBit ) { if( HandleCX(dd) ) break; } if( dd->signals & 1 << dd->notify_port->mp_SigBit ) { if( HandleNotify(dd) ) break; } if( dd->signals & 1 << dd->ipc->command_port->mp_SigBit ) { if( HandleIPC(dd) ) break; } if( dd->win && (dd->signals & 1 << dd->win->UserPort->mp_SigBit) ) { if( HandleWin(dd) ) break; } } } CleanUp( dd, exchange ); exchange = NULL; } void CleanUp( DOE_Data *dd, IPCData *ipc ) { if( dd->win ) CloseWindow( dd->win ); if( dd->notify_port ) { if( dd->notify_handle ) RemoveNotifyRequest( dd->notify_handle ); while( !IsMsgPortEmpty( dd->notify_port) ) ReplyFreeMsg( GetMsg(dd->notify_port) ); DeleteMsgPort( dd->notify_port ); } DeleteCxObjAll( dd->our_cxobj ); if( dd->nb.nb_Port ) { while( !IsMsgPortEmpty(dd->nb.nb_Port) ) ReplyMsg( GetMsg(dd->nb.nb_Port) ); DeleteMsgPort( dd->nb.nb_Port ); } if( dd->sender ) { while( !IsMsgPortEmpty(dd->sender) ) FreeMemH( GetMsg(dd->sender) ); DeleteMsgPort( dd->sender ); } dd->module->lib_OpenCnt--; FreeMemH( dd ); IPC_Free( ipc ); } /********************************************************************/ BOOL OpenWin( DOE_Data *dd ) { // lock the screen if( (dd->screen = LockPubScreen(NULL)) ) { if( (dd->win = OpenWindowTags( NULL, WA_Left, dd->ibox.Left, WA_Top, dd->ibox.Top, WA_Height, dd->screen->Font->ta_YSize + 4, WA_Width, IntuiTextLength( &dd->itext ) + 5, WA_Gadgets, &draggadget, WA_Flags, WFLG_BORDERLESS | WFLG_NEWLOOKMENUS | WFLG_SMART_REFRESH | WFLG_RMBTRAP, WA_IDCMP, IDCMP_MOUSEBUTTONS, WA_AutoAdjust, TRUE, WA_PubScreen, dd->screen, WA_ScreenTitle, (STRPTR) ~0, TAG_DONE)) ) { // register our window, so it does get messages // even it is inactive SetWindowID( dd->win, &dd->id, 0x1400, 0 ); BorderDraw( dd, FALSE ); } UnlockPubScreen( NULL, dd->screen ); } return (BOOL) dd->win; } void BorderDraw( DOE_Data *dd, BOOL invers ) { // flood the port with supplied colour SetRast( dd->win->RPort, dd->itext.BackPen ); // draw a border SetAPen( dd->win->RPort, invers ? 2 : 1 ); Move( dd->win->RPort, 1, dd->win->Height - 1 ); Draw( dd->win->RPort, dd->win->Width-1, dd->win->Height - 1 ); Draw( dd->win->RPort, dd->win->Width-1, 1 ); SetAPen( dd->win->RPort, invers ? 1 : 2 ); Move( dd->win->RPort, 0, dd->win->Height - 1 ); Draw( dd->win->RPort, 0, 0 ); Draw( dd->win->RPort, dd->win->Width-1, 0 ); // set values for the Rastport SetRPAttrs( dd->win->RPort, RPTAG_APen, dd->itext.FrontPen, RPTAG_BPen, dd->itext.BackPen, TAG_DONE ); // print the button text Move( dd->win->RPort, 3, dd->win->RPort->Font->tf_Baseline + 2 ); Text( dd->win->RPort, dd->itext.IText, strlen(dd->itext.IText) ); } /********************************************************************/ // popup menu work // do not be worry, most of this things is only needed to allow: // - unlimited count of entries with their needed submenu // - easier to do the cleanup BOOL InitPopupMenu( DOE_Data *dd ) { dd->entry_count = 0; // init the lists we need NewList( (struct List *) &dd->popmenu.item_list ); NewList( (struct List *) &dd->submenus ); // open the popupmenu above our window dd->popmenu.flags = POPUPMF_ABOVE; // locale pointer, so we must not supply real strings - only ID's dd->popmenu.locale = locale; // since nothing is documented here, I have done what I think: // all brokers must be anywhere in a list and if we have one // node (our broker), we can access the whole list... dd->ptr_node = (struct Node *) dd->our_cxobj; // the objects does work with interrupts, it may a good idea // to protect the access to the list with Disable() Disable(); // go to the head of the list do { dd->ptr_node = dd->ptr_node->ln_Pred; } while( dd->ptr_node->ln_Pred->ln_Pred ); // now we can create our needed lists - we have here 2 + X (!) // first list - MinList with the names of the objects (needed by DoPopUpMenu) // second list - MinList, each node contain again a MinList (third list) // this list is only for easy handling for us // third (and X) list - MinList for submenu, it does also contain a pointer // to the cx_object do { // this counter is used to give each (main) menu item an ID. // since these items have all submenus, you may also give // all the same ID (dopus5.library does only pass them through) dd->entry_count++; // now it's time to create the menu entry... if( (dd->popitem = AllocMemH(mempool, sizeof(PopUpItem))) ) { dd->popitem->item_name = dd->ptr_node->ln_Name; dd->popitem->id = dd->entry_count; // each item has a submenu if( (dd->popitem->data = CreateSubMenu(dd, MSG_ACTIVATE, MSG_REMOVE)) ) dd->popitem->flags = POPUPF_SUB; // the next block is a kind of sorted adding of our nodes // since this are MinList's, it is not possible to use DOpus // list functions here... // at first we need a pointer to the first node dd->compare = (PopUpItem *) dd->popmenu.item_list.mlh_Head; if( IsListEmpty((struct List *) &dd->popmenu.item_list) || Stricmp(dd->popitem->item_name, dd->compare->item_name) < 0 ) // or our new name is lower { AddHead( (struct List *) &dd->popmenu.item_list, (struct Node *) dd->popitem ); } else { // walk through the list until a name is higher than our new name or // the list is no more entries while( dd->compare->node.mln_Succ->mln_Succ && Stricmp(dd->popitem->item_name, ((PopUpItem *) dd->compare->node.mln_Succ)->item_name) > 0 ) dd->compare = (PopUpItem *) dd->compare->node.mln_Succ; // insert the new node before (!) the higher name is coming // or even append it, if no higher entry does exist Insert( (struct List *) &dd->popmenu.item_list, (struct Node *) dd->popitem, (struct Node *) dd->compare ); } } } while( (dd->ptr_node = dd->ptr_node->ln_Succ)->ln_Succ ); // we have not all done now, but we must not access longer the object list, // so we can allow again all stuff Enable(); // adding a barlabel if( (dd->popitem = AllocMemH(mempool, sizeof(PopUpItem))) ) { dd->popitem->item_name = POPUP_BARLABEL; dd->popitem->id = 0; AddTail( (struct List *) &dd->popmenu.item_list, (struct Node *) dd->popitem ); } // adding a item to snap the current settings if( (dd->popitem = AllocMemH(mempool, sizeof(PopUpItem))) ) { dd->popitem->item_name = (STRPTR) MSG_SAVE_POS; dd->popitem->id = POPID_SAVE; dd->popitem->flags = POPUPF_LOCALE; AddTail( (struct List *) &dd->popmenu.item_list, (struct Node *) dd->popitem ); } // and an item to allow to quit directly if( (dd->popitem = AllocMemH(mempool, sizeof(PopUpItem))) ) { dd->popitem->item_name = (STRPTR) MSG_QUIT; dd->popitem->id = POPID_QUIT; dd->popitem->flags = POPUPF_LOCALE; AddTail( (struct List *) &dd->popmenu.item_list, (struct Node *) dd->popitem ); } return TRUE; } // this routine is already prepared to be copied if you need it :) // you must change only small things then... APTR CreateSubMenu( DOE_Data *dd, ULONG from, ULONG to ) { PopUpItem *popitem; if( (dd->submenu_node = AllocMemH(mempool, sizeof(SubMenu_Node))) ) { // init the list NewList( (struct List *) &dd->submenu_node->submenu ); // getting the items to show for( dd->a4 = from; dd->a4 <= to; dd->a4++ ) { // allocate a node if( (popitem = AllocMemH(mempool, sizeof(PopUpItem))) ) { // fill the node popitem->item_name = (STRPTR) dd->a4; popitem->flags = POPUPF_LOCALE; popitem->id = dd->a4; popitem->data = dd->ptr_node; // pointer to the CX_object switch( dd->a4 ) { case MSG_ACTIVATE : popitem->flags |= POPUPF_CHECKIT; // now it is again result of hard work and // may be wrong... :) // check the current activation state //if( ((STRPTR) dd->ptr_node)[0x0E] & 1 << 1 ) if( ((CX_OBJ *) dd->ptr_node)->flags & 1 << 1 ) popitem->flags |= POPUPF_CHECKED; break; case MSG_APPEAR : case MSG_DISAPPEAR: // checking if this object has a GUI //if( !(((STRPTR) dd->ptr_node)[0x0E] & 1 << 2) ) if( !(((CX_OBJ *) dd->ptr_node)->flags & 1 << 2) ) popitem->flags |= POPUPF_DISABLED; } // add the popitem node to the submenu list AddTail( (struct List *) &dd->submenu_node->submenu, (struct Node *) popitem ); } } // add the submenu list to the second list, so we can free it later all easily AddTail( (struct List *) &dd->submenus, (struct Node *) dd->submenu_node ); return &dd->submenu_node->submenu; } return NULL; } // this routines should be clear for everyone... void ClearPopupMenu( DOE_Data *dd ) { while( !IsListEmpty((struct List *) &dd->popmenu.item_list) ) FreeMemH( RemHead((struct List *) &dd->popmenu.item_list) ); while( !IsListEmpty((struct List *) &dd->submenus) ) { dd->submenu_node = (SubMenu_Node *) RemHead((struct List *) &dd->submenus); while( !IsListEmpty((struct List *) &dd->submenu_node->submenu) ) FreeMemH( RemHead((struct List *) &dd->submenu_node->submenu) ); FreeMemH( dd->submenu_node ); } } BOOL DoMenu( DOE_Data *dd ) { // preparing the popupmenu if( InitPopupMenu(dd) ) { // start the popupmenu if( DoPopUpMenu(dd->win, &dd->popmenu, &dd->popitem, MENUDOWN) != -1 ) { // if the previous call does return, dd->popitem contains the user selection switch( dd->popitem->id ) { case POPID_SAVE : WriteConfig( dd ); break; case POPID_QUIT : dd->stop = TRUE; break; case MSG_ACTIVATE: case MSG_APPEAR: case MSG_DISAPPEAR: case MSG_REMOVE: // create a fake CxMsg (not documented...) // and send it to the choosed CxObj SendCxMsg( (CX_OBJ *) dd->popitem->data, // send it to... (dd->popitem->id == MSG_ACTIVATE ? (dd->popitem->flags & POPUPF_CHECKED ? CXCMD_ENABLE : CXCMD_DISABLE) : (dd->popitem->id - MSG_ACTIVATE)*2 + 17 ), dd->sender ); // use this port to reply to break; } } // free the menu ClearPopupMenu( dd ); } return dd->stop; } /********************************************************************/ // handling routines BOOL HandleWin( DOE_Data *dd ) { while( !dd->stop && (dd->messages = GetMsg(dd->win->UserPort)) ) { // since we are not interested in other messages, we use a simple "if" if( ((struct IntuiMessage *) dd->messages)->Class == IDCMP_MOUSEBUTTONS && ((struct IntuiMessage *) dd->messages)->Code == MENUDOWN ) //&& //((ULONG) WhichLayer(&dd->screen->LayerInfo, dd->screen->MouseX, dd->screen->MouseY)) == ((ULONG) dd->win->WLayer) ) { // since we have no real gadget, the window must be activated // else the popup menu may be in some cases not selectable ActivateWindow( dd->win ); // make our window "selected" BorderDraw( dd, TRUE ); dd->stop = DoMenu( dd ); // "unselect" BorderDraw( dd, FALSE ); // deactivate our window again (will activate the previous // activated window, if available) if( dd->win->NextWindow ) ActivateWindow( dd->win->NextWindow ); else dd->win->Flags ^= WFLG_WINDOWACTIVE; } ReplyMsg( dd->messages ); } return dd->stop; } BOOL HandleCX( DOE_Data *dd ) { while( !dd->stop && (dd->messages = GetMsg(dd->nb.nb_Port)) ) { // on this place we can use some variables for other work... dd->a4 = CxMsgType( (CxMsg *) dd->messages ); dd->signals = CxMsgID((CxMsg *) dd->messages); // should be so fast as possible... ReplyMsg( dd->messages ); if( dd->a4 == CXM_COMMAND ) { switch( dd->signals ) { case CXCMD_DISABLE: // since we are do not handle any // other things than our window, it // is a little bit useless to disable/ // enable, but anyway we do it... :) ActivateCxObj( dd->our_cxobj, FALSE ); break; case CXCMD_ENABLE: ActivateCxObj( dd->our_cxobj, TRUE ); break; case CXCMD_APPEAR: if( !dd->win ) { OpenWin( dd ); } else WindowToFront( dd->win ); break; case CXCMD_DISAPPEAR: if( dd->win ) { // save our current position temporally dd->ibox.Left = dd->win->LeftEdge; dd->ibox.Top = dd->win->TopEdge; CloseWindow( dd->win ); dd->win = NULL; } break; case CXCMD_KILL: dd->stop = TRUE; break; /* it seems this value needs a special flag in the newbroker structure and so no messages of this ID does arrive here... case CXCMD_LIST_CHG: break; */ } } } return dd->stop; } BOOL HandleNotify( DOE_Data *dd ) { while( !dd->stop && (dd->messages = GetMsg(dd->notify_port)) ) { switch( ((DOpusNotify *) dd->messages)->dn_Type ) { case DN_OPUS_QUIT : dd->stop = TRUE; break; case DN_CLOSE_WORKBENCH: case DN_OPUS_HIDE : // storing our current window state dd->flags = dd->win ? TRUE : FALSE; SendCxMsg( (CX_OBJ *) dd->our_cxobj, CXCMD_DISAPPEAR, dd->sender ); break; case DN_OPEN_WORKBENCH: case DN_RESET_WORKBENCH: case DN_OPUS_SHOW : if( dd->flags ) SendCxMsg( (CX_OBJ *) dd->our_cxobj, CXCMD_APPEAR, dd->sender ); break; } ReplyFreeMsg( dd->messages ); } return dd->stop; } BOOL HandleIPC( DOE_Data *dd ) { while( !dd->stop && (dd->messages = GetMsg(dd->ipc->command_port)) ) { if( ((IPCMessage *) dd->messages)->command & IPCCMD_QUIT ) { dd->stop = TRUE; } else { if( ((IPCMessage *) dd->messages)->command & IPCCMD_SHOW ) { SendCxMsg((CX_OBJ *) dd->our_cxobj, CXCMD_APPEAR, dd->sender ); } if( ((IPCMessage *) dd->messages)->command & IPCCMD_NAME ) { // make a copy... strncpy( dd->name, ((PassData *) ((IPCMessage *) dd->messages)->data_free)->name, 11 )[11] = 0; // if the supplied name is empty, it does fallback to the buildin name dd->itext.IText = strlen(dd->name) ? dd->name : DOpusGetString( locale, MSG_TEXT ); } if( ((IPCMessage *) dd->messages)->command & IPCCMD_BGC ) { dd->itext.BackPen = ((PassData *) ((IPCMessage *) dd->messages)->data_free)->BackPen; } if( ((IPCMessage *) dd->messages)->command & IPCCMD_TC ) { dd->itext.FrontPen = ((PassData *) ((IPCMessage *) dd->messages)->data_free)->FrontPen; } if( dd->win ) { // save our current position temporally dd->ibox.Left = dd->win->LeftEdge; dd->ibox.Top = dd->win->TopEdge; if( ((IPCMessage *) dd->messages)->command & IPCCMD_NAME ) { // changing the name does require closing and reopening // of the window since the window size depends from the // name... (and font) CloseWindow( dd->win ); OpenWin( dd ); } if( ((IPCMessage *) dd->messages)->command & (IPCCMD_BGC | IPCCMD_TC) ) { BorderDraw( dd, FALSE ); } if( ((IPCMessage *) dd->messages)->command & IPCCMD_HIDE ) { SendCxMsg((CX_OBJ *) dd->our_cxobj, CXCMD_DISAPPEAR, dd->sender ); } } } IPC_Reply( dd->messages ); } return dd->stop; } /********************************************************************/ BOOL SendCxMsg( CX_OBJ *cxobj, ULONG type, struct MsgPort *reply_to ) { FakeMsg *fmsg; // create a fake CxMsg (not documented..., size is 232 bytes) // and send it to the choosed CxObj if( (fmsg = AllocMemH(mempool, 232)) ) { fmsg->msg.mn_Node.ln_Type = NT_MESSAGE; fmsg->msg.mn_Length = 232; fmsg->Code = CXM_COMMAND; fmsg->msg.mn_ReplyPort = reply_to; fmsg->ID = type; PutMsg( cxobj->cx_port, (struct Message *) fmsg ); return TRUE; } return FALSE; } /********************************************************************/ // saving/reading the config // normally I use for this an own file, but since here is only to // write some small values... :) // the following include is only needed to use some defines of it #include <libraries/iffparse.h> // now we are doing some ID's // each data block, which should be recognizeable must have an ID // (=header) #define DOE_ID MAKE_ID('D','O','E','X') #define LEFT_TOP MAKE_ID('L','E','T','E') #define COLOURS MAKE_ID('C','O','L','R') #define NEW_NAME MAKE_ID('N','A','M','E') BOOL WriteConfig( DOE_Data *dd ) { APTR iffhandle; ULONG size; // open our config file for writing if( (iffhandle = IFFOpen(CONFIG_FILE, IFF_WRITE, DOE_ID)) ) { // here you can see it is possible to write more than one value // with one step, they must only follow each other... IFFWriteChunk( iffhandle, &dd->win->LeftEdge, LEFT_TOP, sizeof(WORD) * 2 ); IFFWriteChunk( iffhandle, &dd->itext.FrontPen, COLOURS, sizeof(UBYTE) * 2 ); if( (size = strlen(dd->name)) ) { // it's a nice idea to write the \0 of the string too, // it does save us work on reading the data IFFWriteChunk( iffhandle, dd->name, NEW_NAME, size + 1 ); } IFFClose( iffhandle ); return 0; }; return 1; } // also simple to understand... BOOL ReadConfig( DOE_Data *dd ) { APTR iffhandle; ULONG nextchunk; // open the config file for reading if( (iffhandle = IFFOpen(CONFIG_FILE, IFF_READ, DOE_ID)) ) { // IFFNextChunk() does return the next ID (or NULL if there is none) // and so we can switch here while( (nextchunk = IFFNextChunk(iffhandle, 0)) ) { switch( nextchunk ) { case LEFT_TOP: IFFReadChunkBytes(iffhandle, &dd->ibox, sizeof(WORD) * 2 ); break; case COLOURS : IFFReadChunkBytes(iffhandle, &dd->itext.FrontPen, sizeof(UBYTE) * 2 ); break; case NEW_NAME: // if a string should be readed, it is needed to use the // string alone in a chunk or at least to have it at the // end of a structure - or - // if you do this not, you must always write the whole // structure // if you try to read an alone written string, you // must always set the size to read to the lenght of // you string buffer IFFReadChunkBytes(iffhandle, dd->name, 16 ); break; }; }; IFFClose( iffhandle ); return 0; }; return 1; }